//
//  YFCameraViewController.m
//  CamerDemo
//
//  Created by Winny Zhang on 2019/3/30.
//  Copyright © 2019 Winny Zhang. All rights reserved.
//

#import "YFCameraViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import "YFPlayer.h"
#import "YFCameraProgress.h"
#import <Photos/Photos.h>
#import "DeviceOrientation.h"
#import "YFImagePicker.h"
#import "HJNavigationViewController.h"
#import "HJAddVC.h"

typedef void (^ConfigCameraAction)(AVCaptureDevice *device);

@interface YFCameraViewController ()<AVCaptureFileOutputRecordingDelegate, UIGestureRecognizerDelegate, DeviceOrientationDelegate> {
    
    DeviceOrientation *deviceMotion;
}

#pragma mark - 相机界面UI属性相关
/**
 背景 ImageView
 */
 @property (weak, nonatomic) IBOutlet UIImageView *bgView;
/**
 关闭相机 按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *dismissButton;
/**
 闪光灯开关 按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *flashButton;
/**
 切换摄像头 按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *changeCameraButton;
/**
 取消图片/视频 按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *cancelButton;
/**
 确定 使用图片/视频 按钮
 */
@property (weak, nonatomic) IBOutlet UIButton *confirmButton;
/**
 拍照/拍摄 ImageView
 */
@property (weak, nonatomic) IBOutlet UIImageView *cameraImageView;

/**
 录制进度圆环 View
 */
@property (weak, nonatomic) IBOutlet YFCameraProgress *progress;


/**
 聚焦指示 ImageView
 */
@property (strong, nonatomic) UIImageView *cursor;


#pragma mark - 用于动画的相关约束
/**
 取消按钮中心约束
 */
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cancelButtonConstraintCenterX;
/**
 确定按钮之心约束
 */
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *confirmButtonConstraintCenterX;
/**
 提示 Label
 */
@property (weak, nonatomic) IBOutlet UILabel *tipLabel;


#pragma mark - 操作相机相关属性
/**
 负责输入和输出设备之间的数据传递
 */
@property(nonatomic)AVCaptureSession *session;
/**
 负责从AVCaptureDevice获得输入数据
 */
@property (strong,nonatomic) AVCaptureDeviceInput *captureDeviceInput;
/**
 视频输出流
 */
@property (strong,nonatomic) AVCaptureMovieFileOutput *captureMovieFileOutput;

/**
 头像输出流
 */
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutput;
/**
 图像预览层，实时显示捕获的图像
 */
@property(nonatomic)AVCaptureVideoPreviewLayer *previewLayer;

/**
 录制视频最长时间
 */
@property (nonatomic, assign) NSInteger recordingSeconds;

/**
 是否正在对焦
 */
@property (nonatomic, assign) BOOL isFocusing;

/**
 焦距最小值
 */
@property (nonatomic, assign) CGFloat minZoomFactor;

/**
 焦距最大值
 */
@property (nonatomic, assign) CGFloat maxZoomFactor;

/**
 相机当前焦距
 */
@property (nonatomic, assign) CGFloat currentZommFactor;


#pragma mark - 相机输出相关属性
/**
 拍照后的 UIImage
 */
@property (strong, nonatomic) UIImage *photoImage;
/**
 用来展示拍照照片的 UIImageView
 */
@property (strong, nonatomic) UIImageView *photoImageView;
/**
 保存视频的URL
 */
@property (nonatomic, strong) NSURL *saveVideoURL;

/**
 视频播放器
 */
@property (nonatomic, strong) YFPlayer *player;



#pragma mark - 多任务相关
//后台任务标识
@property (assign,nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;

@property (assign,nonatomic) UIBackgroundTaskIdentifier lastBackgroundTaskIdentifier;

#pragma mark - 拍照或拍摄相关
/**
 记录长按手势
 */
@property (nonatomic, strong) UILongPressGestureRecognizer *longPress;


@end

@implementation YFCameraViewController

- (BOOL)prefersStatusBarHidden {
    return YES;
}

- (void)dealloc {
    LKLog(@"释放了 %s", __func__);
    [self removeNotification];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.session startRunning];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [UIApplication sharedApplication].statusBarHidden = NO;
    [self.session stopRunning];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initSubViews];
    [self initCamera];
    
    [self setIsTakePhoto:_isTakePhoto];
}

#pragma mark - 设置基本UI
- (void)initSubViews {
    // 圆角
    self.cameraImageView.layer.masksToBounds = YES;
    self.cameraImageView.layer.cornerRadius = _cameraImageView.frame.size.height * 0.5;
    self.progress.layer.masksToBounds = YES;
    self.progress.layer.cornerRadius = _progress.frame.size.height * 0.5;
    // 渐变色
//    CAGradientLayer *cameraButtonGradient = [CAGradientLayer layer];
//    cameraButtonGradient.frame = _cameraImageView.bounds;
//    CGColorRef startColor = [UIColor colorWithRed:254/255.0 green:106/255.0 blue:127/255.0 alpha:1].CGColor;
//    CGColorRef endColor = [UIColor colorWithRed:255/255.0 green:137/255.0 blue:128/255.0 alpha:1].CGColor;
//    cameraButtonGradient.colors = @[(__bridge id)startColor, (__bridge id)endColor];
//    cameraButtonGradient.startPoint = CGPointMake(0, 0);
//    cameraButtonGradient.endPoint = CGPointMake(1, 0);
//    [self.cameraImageView.layer insertSublayer:cameraButtonGradient atIndex:0];
    [self.cameraImageView setBackgroundColor:[UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:1.0]];
    // 添加点击手势
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(takePhotoOrRecording:)];
    tap.numberOfTapsRequired = 1;
    
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(takePhotoOrRecording:)];
    longPress.minimumPressDuration = 1;
    
    [self.cameraImageView addGestureRecognizer:tap];
    [self.cameraImageView addGestureRecognizer:longPress];
    
    self.longPress = longPress;
    
    // 点按聚焦
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapScreen:)];
    [self.bgView addGestureRecognizer:tapGesture];
    
    // 捏合调焦
    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(zoomChanged:)];
    pinch.delegate = self;
    [self.bgView addGestureRecognizer:pinch];
    
    // 聚焦指示
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"img_camera_cursor"]];
    imageView.frame = CGRectMake(0, 0, 70, 70);
    imageView.center = self.view.center;
    imageView.hidden = YES;
    [self.view addSubview:imageView];
    self.cursor = imageView;
}

#pragma mark - 初始化相机
- (void)initCamera {
    
    if (self.maxSeconds == 0) {
        self.maxSeconds = 15;
    }
    
    self.session = [[AVCaptureSession alloc] init];
    
    // 设置分辨率
    if ([self.session canSetSessionPreset:AVCaptureSessionPresetHigh]) {
        self.session.sessionPreset = AVCaptureSessionPresetHigh;
    }
   
    // 拿到后置摄像头
    AVCaptureDevice *captureDevice = [self cameraDevicePosition:(AVCaptureDevicePositionBack)];
    
    // 初始化输入设置
    NSError *error = nil;
    self.captureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];
    NSAssert(error == nil, ([NSString stringWithFormat:@"取得设备输入对象时出错，错误原因：%@", error.localizedDescription]));
    
    // 将输入设备添加到会话
    if ([self.session canAddInput:_captureDeviceInput]) {
        [self.session addInput:_captureDeviceInput];
    }
    
    // 添加一个音频输入设备
    AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio].firstObject;
    // 添加音频输入设备
    error = nil;
    AVCaptureDeviceInput *audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:&error];
    NSAssert(error == nil, ([NSString stringWithFormat:@"取得设备输入对象时出错，错误原因：%@", error.localizedDescription]));
    
    if ([self.session canAddInput:audioCaptureDeviceInput]) {
        [self.session addInput:audioCaptureDeviceInput];
    }
    
    // 视频输出对象
    self.captureMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
    self.captureMovieFileOutput.movieFragmentInterval = kCMTimeInvalid;
    
    // 图片输出对象
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSeetings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    [self.imageOutput setOutputSettings:outputSeetings];
    
    // 将图片输出对象添加到会话
    if ([self.session canAddOutput:_imageOutput]) {
        [self.session addOutput:_imageOutput];
    }
    
    // 设置防抖
    AVCaptureConnection *connection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    if ([connection isVideoStabilizationSupported]) {
        connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeCinematic;
    }
    
    // 将输出设备添加会话
    if ([self.session canAddOutput:_captureMovieFileOutput]) {
        [self.session addOutput:_captureMovieFileOutput];
    }
    
    // 预览层
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session];
    self.previewLayer.frame = [UIScreen mainScreen].bounds;
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.bgView.layer addSublayer:_previewLayer];
    
    // 添加通知
    [self addNotificationWithDevice:captureDevice];
    [self addNotifivaitonToScreenChanged];
    
    // 设置输出方向
    // 处理图片方向
    AVCaptureConnection *imageConnection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    imageConnection.videoOrientation = [self.previewLayer connection].videoOrientation;
    // 处理视频方向
    AVCaptureConnection *videoConnection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    videoConnection.videoOrientation = [self.previewLayer connection].videoOrientation;
}

#pragma mark -  添加一些通知
- (void)addNotificationWithDevice:(AVCaptureDevice *)device {
    
    // 开启区域监测自动捕获，用于自动对焦
    [self configCameraAction:^(AVCaptureDevice *device) {
        device.subjectAreaChangeMonitoringEnabled = YES;
    }];
    NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
    
    //捕获区域发生改变
    [notificationCenter addObserver:self selector:@selector(subjectAreaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:device];
}

/**
 会话出错的通知，需要的时候添加
 */
-(void)addNotificationToCaptureSession:(AVCaptureSession *)captureSession{
    NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
    //会话出错
    [notificationCenter addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:captureSession];
}

- (void)addNotifivaitonToScreenChanged {
    deviceMotion = [[DeviceOrientation alloc]initWithDelegate:self];
    [deviceMotion startMonitor];
}

#pragma mark - 移除通知
-(void)removeNotificationFromDevice:(AVCaptureDevice *)captureDevice{
    NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
    [notificationCenter removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];
}
/**
 *  移除所有通知
 */
-(void)removeNotification {
    [deviceMotion stop];
    NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
    [notificationCenter removeObserver:self];
}

#pragma mark - 按钮点击方法
/**
 关闭相机
 */
- (IBAction)dismissButtonClicked {
    [self cloaseCamera];
}
/**
 切换前后摄像头
 */
- (IBAction)changeCameraButtonClicked:(UIButton *)sender {
    sender.selected = !sender.selected;
    [self changeCameraTofront:sender.selected];
}
/**
 切换闪光灯
 */
- (IBAction)flashButtonClicked:(UIButton *)sender {
    sender.selected = !sender.selected;
    
    if (sender.selected) {
        [ self setFlashMode:AVCaptureFlashModeOn];
    } else {
        [self setFlashMode:(AVCaptureFlashModeOff)];
    }
    
   
}
/**
 取消照片/视屏 重新拍摄
 */
- (IBAction)cancelButtonClicked:(id)sender {
    // 还原镜头焦距
    __weak typeof(self) weakSelf = self;
    [self configCameraAction:^(AVCaptureDevice *device) {
        device.videoZoomFactor = weakSelf.minZoomFactor;
    }];
    
    
    [self dismissCancelAndConfirmButtons];
}
/**
 使用照片/视屏
 */
- (IBAction)confirmButtonClicked:(id)sender {
    // 还原镜头焦距
    __weak typeof(self) weakSelf = self;
    [self configCameraAction:^(AVCaptureDevice *device) {
        device.videoZoomFactor = weakSelf.minZoomFactor;
    }];
    
    [self.player stopPlaying];
    self.player.hidden = YES;
    
    [self cloaseCamera];
    
    if (_completion) {
        if (_photoImage) {
            [self saveImage:_photoImage albumName:@"乐见"];
            _completion(YES, _photoImage, nil, nil, 0);
        }
        if (_saveVideoURL) {
            [self saveVideo:_saveVideoURL albumName:@"乐见"];
            long long videoDuration = [self durationWithVideo:_saveVideoURL];
            UIImage *videoFirstFrameImage = [self videoPreViewImage:_saveVideoURL];
            _completion(NO, nil, _saveVideoURL, videoFirstFrameImage, videoDuration);
        }
    }
}



#pragma mark - 手势方法
- (void)takePhotoOrRecording:(UIGestureRecognizer *)gesture {
    /// 拍照
    if ([gesture isKindOfClass:[UITapGestureRecognizer class]]) {
        
        self.tipLabel.hidden = YES;
        
        // NSLog(@"单击Tap");
        AVCaptureConnection *connect = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
        
        AVCaptureDevicePosition currentPosition = [self.captureDeviceInput device].position;
        if (currentPosition == AVCaptureDevicePositionUnspecified || currentPosition == AVCaptureDevicePositionFront) {
            connect.videoMirrored = YES;
        } else {
            connect.videoMirrored = NO;
        }
        __weak typeof(self) weakSelf = self;
        [self.imageOutput captureStillImageAsynchronouslyFromConnection:connect completionHandler:^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error) {
            NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [UIImage imageWithData:jpegData];
            
            if (!weakSelf.photoImageView) {
                weakSelf.photoImageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
                weakSelf.photoImageView.layer.backgroundColor = [UIColor blackColor].CGColor;
                weakSelf.photoImageView.clipsToBounds = YES;
                [weakSelf.bgView addSubview:self.photoImageView];
            }
            
            if (image.size.width > image.size.height) {
                weakSelf.photoImageView.contentMode = UIViewContentModeScaleAspectFit;
            } else {
                weakSelf.photoImageView.contentMode = UIViewContentModeScaleAspectFill;
            }
            
            weakSelf.photoImageView.hidden = NO;
            weakSelf.photoImageView.image = image;
            [weakSelf showCancelAndConfirmButtons];
            weakSelf.saveVideoURL = nil;
            weakSelf.photoImage = image;
        }];
    }
    
    // 摄像
    if ([gesture isKindOfClass:[UILongPressGestureRecognizer class]]) {
        
        self.tipLabel.hidden = YES;
        
        if (gesture.state == UIGestureRecognizerStateBegan) {
           //  NSLog(@"开始长按 ... LongPress");
            [self recordButtonAnimate];
            [self startRecording];
        }
        if ((gesture.state == UIGestureRecognizerStateEnded)) {
            // NSLog(@"结束长按！");
            if ([self.captureMovieFileOutput isRecording]) {
                [self endRecord];
                [self restoreRecordButton];
                [self showCancelAndConfirmButtons];
            }
        }
    }
}

/**
 手势对焦

 @param tapGesture 手势
 */
-(void)tapScreen:(UITapGestureRecognizer *)tapGesture{
    if ([self.session isRunning]) {
        CGPoint point= [tapGesture locationInView:self.bgView];
        //将UI坐标转化为摄像头坐标
        CGPoint cameraPoint= [self.previewLayer captureDevicePointOfInterestForPoint:point];
        [self setFocusCursorWithPoint:point];
        [self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposureMode:AVCaptureExposureModeContinuousAutoExposure atPoint:cameraPoint];
    }
}

/**
 捏合调焦

 @param gesture 捏合手势
 */
- (void)zoomChanged:(UIPinchGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateBegan ||
        gesture.state == UIGestureRecognizerStateChanged)
    {
        CGFloat currentZoomFactor = self.currentZommFactor * gesture.scale;
        
        if (currentZoomFactor < self.maxZoomFactor &&
            currentZoomFactor > self.minZoomFactor){
            
            // 改变镜头焦距
            [self configCameraAction:^(AVCaptureDevice *device) {
                device.videoZoomFactor = currentZoomFactor;
            }];
        }
    }
}

#pragma mark - 取消按钮和确认按钮动画
- (void)showCancelAndConfirmButtons {
    
    [self restoreRecordButton];
    [self.progress restore];
    [self.cursor removeFromSuperview];
    
    self.cancelButton.hidden = NO;
    self.cancelButton.alpha = 0;
    self.confirmButton.hidden = NO;
    self.confirmButton.alpha = 0;
    self.cancelButtonConstraintCenterX.constant = -([UIScreen mainScreen].bounds.size.width * 0.25);
    self.confirmButtonConstraintCenterX.constant = [UIScreen mainScreen].bounds.size.width * 0.25;
    [UIView animateWithDuration:0.25 animations:^{
        self.cancelButton.alpha = 1;
        self.confirmButton.alpha = 1;
        self.cameraImageView.alpha = 0;
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        self.cameraImageView.hidden = YES;
        self.cameraImageView.alpha = 1;
    }];
}
- (void)dismissCancelAndConfirmButtons {
    
    
    self.tipLabel.hidden = NO;
    [self.view addSubview:self.cursor];
    
    [self.player stopPlaying];
    self.player.hidden = YES;
    
    self.cameraImageView.alpha = 0;
    self.cameraImageView.hidden = NO;
    
    self.cancelButtonConstraintCenterX.constant = 0;
    self.confirmButtonConstraintCenterX.constant = 0;
    
    [UIView animateWithDuration:0.25 animations:^{
        self.cancelButton.alpha = 0;
        self.confirmButton.alpha = 0;
        self.cameraImageView.alpha = 1;
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        self.cancelButton.hidden = YES;
        self.confirmButton.hidden = YES;
    }];
    
    if (!self.photoImageView.hidden) {
        self.photoImageView.hidden = YES;
    }
    
    self.lastBackgroundTaskIdentifier = self.backgroundTaskIdentifier;
    self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}

#pragma mark - 录制视频圆环动画
- (void) recordButtonAnimate {
    self.progress.hidden = NO;
    self.progress.alpha = 0;
    self.progress.transform = CGAffineTransformMakeScale(0.5, 0.5);
    self.progress.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
    [UIView animateWithDuration:0.5 animations:^{
        self.cameraImageView.transform = CGAffineTransformMakeScale(0.75, 0.75);
        self.progress.transform = CGAffineTransformIdentity;
        self.progress.alpha = 1;
    } completion:^(BOOL finished) {
    }];
}

- (void) restoreRecordButton {
   self.cameraImageView.transform = CGAffineTransformIdentity;
    self.progress.transform = CGAffineTransformIdentity;
    self.progress.hidden = YES;
}

#pragma mark - 开始录制
- (void)startRecording {
    // NSLog(@"开始录制");
    // 根据输出设备获得连接
    AVCaptureConnection *connect = [self.captureMovieFileOutput connectionWithMediaType:(AVMediaTypeVideo)];
    // 根据连接获得视频输出数据
    if (![self.captureMovieFileOutput isRecording]) {
        // 如果支持多任务则开始多任务
        if ([[UIDevice currentDevice] isMultitaskingSupported]) {
            self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
        }
        if (_saveVideoURL) {
            [[NSFileManager defaultManager] removeItemAtURL:_saveVideoURL error:nil];
        }
        
        AVCaptureDevicePosition currentPosition = [self.captureDeviceInput device].position;
        if (currentPosition == AVCaptureDevicePositionUnspecified || currentPosition == AVCaptureDevicePositionFront) {
            connect.videoMirrored = YES;
        } else {
            connect.videoMirrored = NO;
        }
        NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingString:@"myVideo.mp4"];
         NSLog(@"视频保存路径：%@", outputFilePath);
        NSURL *fileURL = [NSURL fileURLWithPath:outputFilePath];
         NSLog(@"视频 URL：%@", fileURL);
        [self.captureMovieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];
    } else {
        [self.captureMovieFileOutput stopRecording];
    }
}

- (void)endRecord {
    [self.captureMovieFileOutput stopRecording];
}

#pragma mark - AVCaptureFileOutputRecordingDelegate
// 开始录制代理
- (void)captureOutput:(AVCaptureFileOutput *)output didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections {
    self.recordingSeconds = _maxSeconds;
    self.progress.totalProgress = _maxSeconds - 1;
    [self performSelector:@selector(continueRecording:) withObject:fileURL afterDelay:1];
}

// 录制完成
- (void)captureOutput:(AVCaptureFileOutput *)output didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections error:(NSError *)error {
    // NSLog(@"视频录制完成。");
    self.photoImage = nil;
    self.photoImageView.image = nil;
    self.saveVideoURL = outputFileURL;
    // 设置播放器
    if (!_player) {
        self.player = [[YFPlayer alloc] initWithFrame:[UIScreen mainScreen].bounds onView:self.bgView videoURL:outputFileURL];
    } else {
        self.player.videoURL = outputFileURL;
        self.player.hidden = NO;
    }
    AVCaptureConnection *videoConnection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    if (videoConnection.videoOrientation == AVCaptureVideoOrientationLandscapeRight) {
        self.player.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    } else {
        self.player.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    }
}

#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
        self.currentZommFactor = [self.captureDeviceInput device].videoZoomFactor;
    }
    return YES;
}

#pragma mark - 录制视频持续时间
- (void)continueRecording:(NSURL *)fileURL {
    if ([self.captureMovieFileOutput isRecording]) {
        -- self.recordingSeconds;
        if (self.recordingSeconds > 0) {
            if (_maxSeconds - _recordingSeconds >= 1) {
                // 设置圆环
                // NSLog(@"%zd", self.recordingSeconds);
                // self.processView.timeMax = self.recordingSeconds;
            }
            [self performSelector:@selector(continueRecording:) withObject:fileURL afterDelay:1.0];
        } else {
            if ([self.captureMovieFileOutput isRecording]) {
                [self.captureMovieFileOutput stopRecording];
            }
            // 还原录制按钮
            [self restoreRecordButton];
            [self showCancelAndConfirmButtons];
        }
    }
}

#pragma mark - 关闭相机
- (void)cloaseCamera {
    [self dismissViewControllerAnimated:YES completion:nil];
}


#pragma mark - 操作相机相关方法
/**
 统一设置属性
 */
- (void)configCameraAction:(ConfigCameraAction)action {
    AVCaptureDevice *device = [self.captureDeviceInput device];
    NSError *error = nil;
    
    if ([device lockForConfiguration:&error]) {
        
        /// 闪光灯自动
        if ([device isFlashModeSupported:(AVCaptureFlashModeAuto)]) {
            device.flashMode = AVCaptureFlashModeAuto;
        }
        // 曝光
        if ([device isExposureModeSupported:(AVCaptureExposureModeAutoExpose)]) {
            device.exposureMode = AVCaptureExposureModeAutoExpose;
        }
        // 连续自动曝光
        if([device isExposureModeSupported:(AVCaptureExposureModeContinuousAutoExposure)]) {
            device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
        }
        // 自动白光平衡
        if ([device isWhiteBalanceModeSupported:(AVCaptureWhiteBalanceModeAutoWhiteBalance)]) {
            device.whiteBalanceMode = AVCaptureWhiteBalanceModeAutoWhiteBalance;
        }
        // 连续自动白光平衡
        if ([device isWhiteBalanceModeSupported:(AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance)]) {
            device.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
        }
        if (action) {
            action(device);
        }
        [device unlockForConfiguration];
    } else {
        NSAssert(error == nil,( [NSString stringWithFormat:@"设置设备属性过程发生错误，错误信息：%@", error.localizedDescription]));
    }
}
/**
 获取制定的摄像头

 @param position 摄像头位置 （前/后）
 @return 当前相机设备
 */
- (AVCaptureDevice *)cameraDevicePosition:(AVCaptureDevicePosition)position {
    NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *camera in cameras) {
        if ([camera position] == position) {
            return camera;
        }
    }
    return nil;
}

/**
 切换摄像头

 @param isFront 是否是前置摄像头
 */
- (void)changeCameraTofront:(BOOL)isFront {
    // NSLog(@"切换摄像头");
    AVCaptureDevice *currentDevice = [self.captureDeviceInput device];
    AVCaptureDevicePosition currentPoisition = [currentDevice position];
    [self removeNotificationFromDevice:currentDevice];
    AVCaptureDevice *toDevice;
    // 前摄像头
    AVCaptureDevicePosition tochangePosition = AVCaptureDevicePositionFront;
    if (currentPoisition == AVCaptureDevicePositionUnspecified || currentPoisition == AVCaptureDevicePositionFront) {
        // 后摄像头
        tochangePosition = AVCaptureDevicePositionBack;
    }
    toDevice = [self cameraDevicePosition:tochangePosition];
    [self addNotificationWithDevice:toDevice];
    // 获取要调整的设备输入对象
    AVCaptureDeviceInput *toChangeDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:toDevice error:nil];
    
    // 改变会话的配置前一定要先开启配置，配置完成后提交配置
    [self.session beginConfiguration];
    
    // 移除原来的输入源
    [self.session removeInput:self.captureDeviceInput];
    
    // 移除原来的输出源
    [self.session removeOutput:self.imageOutput];
    
    // 添加新的输入对象
    if ([self.session canAddInput:toChangeDeviceInput]) {
        [self.session addInput:toChangeDeviceInput];
        self.captureDeviceInput = toChangeDeviceInput;
    }
    
    // 添加一个音频输入设备
    AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio].firstObject;
    // 添加音频输入设备
    NSError *error = nil;
    AVCaptureDeviceInput *audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:&error];
    NSAssert(error == nil, ([NSString stringWithFormat:@"取得设备输入对象时出错，错误原因：%@", error.localizedDescription]));

    if ([self.session canAddInput:audioCaptureDeviceInput]) {
        [self.session addInput:audioCaptureDeviceInput];
    }
    
    // 图片输出对象
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSeetings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    [self.imageOutput setOutputSettings:outputSeetings];
    
    // 将图片输出对象添加到会话
    if ([self.session canAddOutput:_imageOutput]) {
        [self.session addOutput:_imageOutput];
    }
    
    // 提交会话配置
    [self.session commitConfiguration];
}

/**
*  设置闪光灯模式
*
*  @param flashMode 闪光灯模式
*/
-(void)setFlashMode:(AVCaptureFlashMode )flashMode{
    [self configCameraAction:^(AVCaptureDevice *device) {
        if ([device isFlashModeSupported:flashMode]) {
            [device setFlashMode:flashMode];
        }
    }];
}
/**
 *  设置聚焦模式
 *
 *  @param focusMode 聚焦模式
 */
-(void)setFocusMode:(AVCaptureFocusMode )focusMode{
    [self configCameraAction:^(AVCaptureDevice *device) {
        if ([device isFocusModeSupported:focusMode]) {
            [device setFocusMode:focusMode];
        }
    }];
}
/**
 *  设置曝光模式
 *
 *  @param exposureMode 曝光模式
 */
-(void)setExposureMode:(AVCaptureExposureMode)exposureMode{
    [self configCameraAction:^(AVCaptureDevice *device) {
        if ([device isExposureModeSupported:exposureMode]) {
            [device setExposureMode:exposureMode];
        }
    }];
}

/**
 *  设置聚焦光标位置
 *
 *  @param point 光标位置
 */
-(void)setFocusCursorWithPoint:(CGPoint)point{
    if (!self.isFocusing) {
        self.isFocusing = YES;
        self.cursor.hidden = NO;
        self.cursor.center = point;
        self.cursor.transform = CGAffineTransformMakeScale(1.25, 1.25);
        self.cursor.alpha = 1.0;
        [UIView animateWithDuration:0.5 animations:^{
            self.cursor.transform = CGAffineTransformIdentity;
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
            [self performSelector:@selector(hiddenFocusCurSorAction) withObject:nil afterDelay:0.5];
        }];
    }
}
- (void)hiddenFocusCurSorAction {
    self.cursor.alpha = 0;
    self.cursor.hidden = YES;
    self.isFocusing = NO;
}

/**
 *  设置聚焦点
 *
 *  @param point 聚焦点
 */
-(void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{
    [self configCameraAction:^(AVCaptureDevice *device) {
        if ([device isExposureModeSupported:exposureMode]) {
            [device setExposureMode:exposureMode];
        }
        if ([device isFocusModeSupported:focusMode]) {
            [device setFocusMode:focusMode];
        }
        if ([device isFocusPointOfInterestSupported]) {
            [device setFocusPointOfInterest:point];
        }
        if ([device isExposurePointOfInterestSupported]) {
            [device setExposurePointOfInterest:point];
        }
    }];
}


#pragma mark - 通知执行方法
/**
 监测到捕获区域改变

 @param info AVCaptureDevice
 */
- (void)subjectAreaChange:(NSNotification *)info {
    // NSLog(@"监测到捕获区域改变...");
}

/**
 监测到会话出错

 @param info AVCaptureSession
 */
- (void)sessionRuntimeError:(NSNotification *)info {
    // NSLog(@"监测到会话出错...");
}


#pragma mark - DeviceOrientationDelegate
- (void)directionChange:(TgDirection)direction {
    
    // 处理图片方向
    AVCaptureConnection *imageConnection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    // 处理视频方向
    AVCaptureConnection *videoConnection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    
    switch (direction) {
        case TgDirectionPortrait:
            
            imageConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
            videoConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
            
            break;
        case TgDirectionDown:
            
            imageConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
            videoConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
            
            break;
        case TgDirectionRight:
            
            imageConnection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            videoConnection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            
            break;
        case TgDirectionleft:
            
            imageConnection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            videoConnection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            
            break;
            
        default:
            break;
    }
}

#pragma mark - 处理屏幕旋转
/**
 屏幕始终竖屏显示
 */
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

- (BOOL)shouldAutorotate{
    return NO;
}


- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationPortrait;
}


#pragma mark - Setter
- (void)setIsTakePhoto:(BOOL)isTakePhoto {
    _isTakePhoto = isTakePhoto;
    if (isTakePhoto) {
        self.tipLabel.text = @"点击拍照";
        [self.cameraImageView removeGestureRecognizer:self.longPress];
    }
}

/**
 焦距最小值
 */
- (CGFloat)minZoomFactor
{
    CGFloat minZoomFactor = 1.0;
    if (@available(iOS 11.0, *)) {
        
        minZoomFactor = [self.captureDeviceInput device].minAvailableVideoZoomFactor;
    }
    return minZoomFactor;
}


/**
 焦距最大值
 */
- (CGFloat)maxZoomFactor
{
    CGFloat maxZoomFactor = [self.captureDeviceInput device].activeFormat.videoMaxZoomFactor;
    if (@available(iOS 11.0, *)) {
        maxZoomFactor = [self.captureDeviceInput device].maxAvailableVideoZoomFactor;
    }
    
    if (maxZoomFactor > 6.0) {
        maxZoomFactor = 6.0;
    }
    return maxZoomFactor;
}

#pragma mark - 获取视频的第一帧
/**
 获取视频第一帧图像

 @param path 视频路径
 @return UIImage 图像
 */
- (UIImage *)videoPreViewImage:(NSURL *)path {
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:path options:nil];
    AVAssetImageGenerator *assetGen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    assetGen.appliesPreferredTrackTransform = YES;
    assetGen.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;

    CMTime time = CMTimeMakeWithSeconds(0.0, 600);
    NSError *error = nil;
    CMTime actualTime;
    CGImageRef image = [assetGen copyCGImageAtTime:time actualTime:&actualTime error:&error];
    UIImage *videoImage = [[UIImage alloc] initWithCGImage:image];
    CGImageRelease(image);
    
    return videoImage.fixOrientation;
}

#pragma mark - 保存图片
- (void)saveImage:(UIImage *)image albumName:(NSString *)albumName {
    
    __block PHAssetCollection *album = [self loadAlbumWithName:albumName];
    
    __weak typeof(self) weakSelf = self;
    
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        
        if (weakSelf.lastBackgroundTaskIdentifier!= UIBackgroundTaskInvalid) {
            [[UIApplication sharedApplication] endBackgroundTask:weakSelf.lastBackgroundTaskIdentifier];
        }
        
        PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        
        if (albumName) {
            PHObjectPlaceholder *placeholderForCreatedAsset = changeRequest.placeholderForCreatedAsset;
            PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
            [request addAssets:@[placeholderForCreatedAsset]];
        }
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        
    }];
}

#pragma mark - 保存视频到相册
- (void)saveVideo:(NSURL *)videoURL albumName:(NSString *)albumName {
    
    __block PHAssetCollection *album = [self loadAlbumWithName:albumName];
    
    __weak typeof(self) weakSelf = self;
    
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        
        if (weakSelf.lastBackgroundTaskIdentifier!= UIBackgroundTaskInvalid) {
            [[UIApplication sharedApplication] endBackgroundTask:weakSelf.lastBackgroundTaskIdentifier];
        }
        
        PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:videoURL];
        
        if (albumName) {
            PHObjectPlaceholder *placeholderForCreatedAsset = changeRequest.placeholderForCreatedAsset;
            PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
            [request addAssets:@[placeholderForCreatedAsset]];
        }
        
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        
    }];
    
}

#pragma mark - 根据名字获取相册，名字为 nil 时返回相机胶卷，有名字时返回该名字相册
- (PHAssetCollection *)loadAlbumWithName:(NSString *)albumName {
    // 检查授权
    if (!(PHPhotoLibrary.authorizationStatus == PHAuthorizationStatusAuthorized || PHPhotoLibrary.authorizationStatus == PHAuthorizationStatusNotDetermined)) {
        NSLog(@"相册隐私未授权");
        return nil;
    }
    
    __block PHAssetCollection *album = nil;
    
    // 如果未指定相册名称，则自动保存到相机胶卷
    if (albumName == nil) {
        
        PHFetchResult<PHAssetCollection *> *albumList =
        [PHAssetCollection fetchAssetCollectionsWithType:(PHAssetCollectionTypeSmartAlbum)
                                                 subtype:(PHAssetCollectionSubtypeSmartAlbumUserLibrary)
                                                 options:nil];
        
        album = albumList.firstObject;
        
        return album;
        
    }
    // 指定了相册
    //相册不存在
    PHFetchResult<PHAssetCollection *> *albumList =
    [PHAssetCollection fetchAssetCollectionsWithType:(PHAssetCollectionTypeAlbum)
                                             subtype:(PHAssetCollectionSubtypeAny)
                                             options:nil];
    
    [albumList enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        if ([albumName isEqualToString:obj.localizedTitle]) {
            album = obj;
        }
    }];
    
    // 如果相册不存在，创建名为 albumName 的相册
    if (album == nil) {
        
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            
            [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumName];
            
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            
            [albumList enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                
                if ([albumName isEqualToString:obj.localizedTitle]) {
                    album = obj;
                }
            }];
        }];
    }
    return album;
}

#pragma mark - 获取视频时长
- (long long)durationWithVideo:(NSURL *)videoURL {
    NSDictionary *options = [NSDictionary dictionaryWithObject:@(NO) forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:videoURL options:options]; // 初始化视频媒体文件
    long long seconds = 0;
    seconds = urlAsset.duration.value / urlAsset.duration.timescale; // 获取视频总时长, 单位秒
    return seconds;
}

@end
